/************************************************/
/*												*/
/*				BattleManager.cpp				*/
/*												*/
/************************************************/


#include <iostream>

#include <fstream>

#include <ctime>

#include <cctype>

#include <iomanip>

#include "BattleManager.h"


using namespace std;

/************************************************/


BattleManager::BattleManager(Character& P)
{
	cPlayer = &P;

	MinDam = P.getWeapon().getMinDamage();

	MaxDam = P.getWeapon().getMaxDamage();

	CritMult = P.getWeapon().getCriticalMult();

	CritMin = P.getWeapon().getCriticalMin();

	StrMod = P.getStrengthMod();

	LoadMonsters();			

	srand(time(NULL));			

	monster = MonsterList[rand()%NumofMonsters];

	firstRound = 0;
	
}

/************************************************/


void ~BattleManager::BattleManager()
{
	delete [] MonsterList;

	delete cPlayer;
}

/************************************************/


void BattleManager::DispStats()
{
	 if(!firstRound)
	 {
		if(result = MISS)

			cout << " MISS " << endl << endl;

		else if(result = CRITICAL_HIT)

			cout << " CRITICAL HIT " << endl << endl;

		else

			cout << " HIT " << endl << endl;
	 }

	cout << " BATTLE START " << endl << endl;

		 << " Player " 		<< '\t' << 	monster.name << endl;

		 << cPlayer->hitPoints << '\t' <<  monster.hitPoints <<"\tHit Points " << endl;

		 << MinDam 	<< '\t' << 	monster.minDamage << "\tWeapon Minimum Damage " << endl;

		 << MaxDam 	<< '\t' << 	monster.maxDamage << "\tWeapon Maximum Damage " << endl;

		 << cPlayer->strength <<'\t' << monster.strength << "\tStrength " << endl;

		 << cPlayer->dexterity <<'\t' << monster.dexterity << "\tDexterity " << endl;

		 << cPlayer->wisdom << '\t' << monster.wisdom << "\tWisdom" << endl;

 }

  


/************************************************/


				 
CombatResult BattleManager::Fight()
{
	char combatOpt;							

	bool badInput = true;

	bool fightStatus = true;

	const bool	playerAttack = true;

	const bool  CritHit = true;

	firstRound = 0;

	while(fightStatus)
	{						
		while(badInput)
		{
			system("cls");

			DispStats();
			
			cout <<" " << endl << endl;

				 <<" A.  Attack " << endl;

				 <<" R.  Run" << endl;

				 <<" I.  Intimidate " << endl;

			   	 <<" S.  Study Opponent " << endl << endl;

				 <<" Select a combat option: ";

				cin.get(combatOpt);

			switch(tolower(combatOpt))
			{
				case 'a': 
							result = attack(!CritHit, playerAttack)
							badInput = false;
							break;

				case 'i': 
							if (intimidate())
							{
								cPlayer->hitPoints ++;
								return MONSTER_SCARED;
							}

							else
								result = attack(!CritHit, !playerAttack);
								badInput = false;
							break;

				case 'r': 
							if(run())
								return PLAYER_ESCAPED;
					
							else
								result = attack(!CritHit, !playerAttack);
								badInput = false;
							break;

				case 's': 
							if (studyOpp())
								result = attack(CritHit, playerAttack);
					else

							result = attack(!CritHit, !playerAttack);
							badInput = false;
							break;

				default:
						badInput = true;
						

			}

		}

	if(monster.hitPoints <= 0)

		return MONSTER_DEAD;

	if(cPlayer->hitPoints <= 0)

		return PLAYER_DEAD;

	if (MONSTER_DEAD || PLAYER_DEAD || MONSTER_SCARED || PLAYER_ESCAPED)

		fightStatus = false;

		firstRound  = false;

	}
}

/************************************************/

			
AttackResult BattleManager::Attack(const bool critHit, const bool playerAttack)
{
	int	damage=0;

	int PlayerRoll = rollDie();

	int MonsterRoll = rollDie();

	AttackResult stat;
	
	if(playerAttack)
	{	
		if(PlayerRoll >= CritMin || CritHit == true)
		{
			for(int i = 1; i < CritMult; i++)

				damage += genRandNum(MinDam, MaxDam) + StrMod;

				stat = CRITICAL_HIT;
		}
		
		else if(PlayerRoll + baseAttack + StrMod >= monster.armor_bonus)
		{
			damage = genRandNum(MinDam, MaxDam) + StrMod;
			
			stat = HIT;
		}

		else
			return MISS;
		monster.hitPoints -= damage;
	}

	else
	{

			if(MonsterRoll >= monster.criticalMin)
			{
				for(int i = 1; i < monster.criticalMult; i++)

				damage += genRandNum(monster.minDamage, monster.maxDamage) + monster.strength;

				stat = CRITICAL_HIT;
			}

			else if(MonsterRoll + baseAttack + monster.strength >= monster.armor_bonus)
			{
				damage = genRandNum(monster.minDamage, monster.maxDamage) + monster.strength;
				
				stat = HIT;
			}
		
			else
				return MISS;

		cPlayer->hitPoints -= damage;

	}

	return stat;

}

/************************************************/


void BattleManager::LoadMonsters()
{
	ifstream MonsterFile("monsters.txt");

	if(!MonsterFile) 
		
		throw NoMonsterFile_E();

	infile >> NumofMonsters;

	MonsterList = new Monster[NumofMonsters];

	for(int i = 0; i < NumofMonsters; i++)
	{
		MonsterFile >> MonsterList[i].name;

		MonsterFile >> MonsterList[i].strength;

		MonsterFile >> MonsterList[i].dexterity;

		MonsterFile >> MonsterList[i].constitution;

		MonsterFile >> MonsterList[i].wisdom;

		MonsterFile >> MonsterList[i].charisma;

		MonsterFile >> MonsterList[i].weaponName;

		MonsterFile >> MonsterList[i].minDamage;

		MonsterFile >> MonsterList[i].maxDamage;

		MonsterFile >> MonsterList[i].criticalMin;

		MonsterFile >> MonsterList[i].criticalMult;

		MonsterFile >> MonsterList[i].armorName;

		MonsterFile >> MonsterList[i].armorBonus;

		MonsterFile >> MonsterList[i].armorPenalty;

		MonsterFile >> MonsterList[i].maxDexterity;

		MonsterFile >> MonsterList[i].baseAttackBonus;

		MonsterFile >> MonsterList[i].hitPoints;
	}

	MonsterFile.close();

}

/************************************************/


int BattleManager::genRandNum(int low, int high){return rand() % high + low;}

int BattleManager::RollDie(){return rand() % 20 + 1;}

/************************************************/


bool BattleManager::Run()
{
	int PlayerRoll = rollDie() + cPlayer->getDexMod() + cPlayer->getArmor().getPenalty();

	int MonsterRoll = rollDie() + monster.dexterity + monster.wisdom;
	
	if(PlayerRoll >= MonsterRoll)
		return true;

	else
		return false;
}

/************************************************/

bool BattleManager::StudyOpp()
{
	int PlayerRoll = rollDie() + cPlayer->getWisMod();

	int MonsterRoll = rollDie() + monster.dexterity() + monster.armorPenalty;	

	if(PlayerRoll >= MonsterRoll)
		return true;

	else
		return false;
}

/************************************************/

bool BattleManager::Intimidate()
{
	int PlayerRoll = rollDie() + cPlayer->getChaMod();

	int MonsterRoll = rollDie() + monster.wisdom();	

	if(PlayerRoll >= MonsterRoll)
		return true;

	else
		return false;
}

/************************************************/
